﻿using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.VisualStudio;
using Microsoft.VisualStudio.Designer;
using Microsoft.VisualStudio.Designer.Shell;

using System.CodeDom;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.ComponentModel.Design.Serialization;
using System.ComponentModel.Design.Data;

using System.Windows.Forms;
using System.Runtime;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

namespace Adaptive.Foundation.CodeDom.Native
{
    internal sealed class ShellDocumentManager : DocumentManager, IVsSelectionEvents
    {
        // Fields
        private IVsMonitorSelection monitorSelectionService;
        private int selectionEventsCookie;

        // Methods
        public ShellDocumentManager(IServiceProvider dsp)
            : base(dsp)
        {
            this.monitorSelectionService = (IVsMonitorSelection)base.GetService(typeof(IVsMonitorSelection));
            if (this.monitorSelectionService != null)
            {
                this.selectionEventsCookie = this.monitorSelectionService.AdviseSelectionEvents(this);
            }
        }

        public override void Dispose()
        {
            if (this.monitorSelectionService != null)
            {
                this.monitorSelectionService.UnadviseSelectionEvents(this.selectionEventsCookie);
                this.monitorSelectionService = null;
            }
            base.Dispose();
            
            Application.Exit();
        }

        public static IVsHierarchy GetHierarchyForFile(IServiceProvider serviceProvider, string file, out int pItemID)
        {
            IVsUIShellOpenDocument service = (IVsUIShellOpenDocument)serviceProvider.GetService(typeof(IVsUIShellOpenDocument));
            if (service == null)
            {
                throw new SystemException("ASSEMBLYSERVICEMissingService");
            }
            IVsHierarchy[] ppUIH = new IVsHierarchy[1];
            int[] pitemid = new int[1];
            if (service.IsDocumentInAProject(file, ppUIH, pitemid, null) == 0)
            {
                ppUIH[0] = null;
            }
            pItemID = pitemid[0];
            return ppUIH[0];
        }

        private IDesignerHost GetHostFromFrame(IVsWindowFrame frame)
        {
            IntPtr ptr;
            if (frame == null)
            {
                return null;
            }
            object property = null;
            property = frame.GetProperty(-3001);
            IDesignerHost service = null;
            if (property is IServiceProvider)
            {
                service = null;
            }
            if ((service != null) || !(property is IOleServiceProvider))
            {
                return service;
            }
            Guid gUID = Guid.Empty;
            if (((((IOleServiceProvider)property).QueryService(ref gUID, ref gUID, out ptr)) < 0) || (ptr == IntPtr.Zero))
            {
                return null;
            }
            object objectForIUnknown = System.Runtime.InteropServices.Marshal.GetObjectForIUnknown(ptr);
            System.Runtime.InteropServices.Marshal.Release(ptr);
            return (IDesignerHost)objectForIUnknown;
        }

        void IVsSelectionEvents.OnCmdUIContextChanged(int dwCmdUICookie, int fActive)
        {
        }

        void IVsSelectionEvents.OnElementValueChanged(int elementid, object objValueOld, object objValueNew)
        {
            if (elementid == 2)
            {
                IDesignerHost oldDesigner = null;
                IDesignerHost newDesigner = null;
                if (objValueOld != null)
                {
                    oldDesigner = this.GetHostFromFrame((IVsWindowFrame)objValueOld);
                }
                if (objValueNew != null)
                {
                    newDesigner = this.GetHostFromFrame((IVsWindowFrame)objValueNew);
                }
                if ((oldDesigner == newDesigner) && (newDesigner != base.ActiveDesigner))
                {
                    oldDesigner = base.ActiveDesigner;
                }
                if (oldDesigner != newDesigner)
                {
                    base.OnActiveDesignerChanged(new ActiveDesignerEventArgs(oldDesigner, newDesigner));
                }
            }
        }

        void IVsSelectionEvents.OnSelectionChanged(IVsHierarchy pHierOld, int itemidOld, object pMISOld, ISelectionContainer pSCOld, IVsHierarchy pHierNew, int itemidNew, object pMISNew, ISelectionContainer pSCNew)
        {
            try
            {
                if (pSCNew is ISelectionService)
                {
                    base.OnSelectionChanged((ISelectionService)pSCNew);
                }
                else
                {
                    base.OnSelectionChanged(null);
                }
            }
            catch (Exception)
            {
            }
        }

        public override void OnSelectionChanged(ISelectionService selection)
        {
            IDesignerHost activeDesigner = base.ActiveDesigner;
            if ((activeDesigner != null) && ((selection == null) || (selection is ISelectionContainer)))
            {
                ITrackSelection service = (ITrackSelection)activeDesigner.GetService(typeof(ITrackSelection));
                if (service != null)
                {
                    if ((selection is ISelectionContainerOptimized) && (service is ITrackSelectionOptimized))
                    {
                        ((ITrackSelectionOptimized)service).OnSelectChange((ISelectionContainerOptimized)selection);
                    }
                    else
                    {
                        service.OnSelectChange((ISelectionContainer)selection);
                    }
                }
            }
        }
    }
}
